#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
全局音频队列管理器
Global Audio Queue Manager

提供全局音频播放队列管理，支持优先级播放和打断机制
Provides global audio playback queue management with priority support and interrupt mechanism
"""

import threading
import time
import logging
from typing import Optional, Dict, Any, List, Callable, Tuple
from queue import PriorityQueue, Empty
from enum import IntEnum
from dataclasses import dataclass, field
from pathlib import Path


class AudioPriority(IntEnum):
    """
    音频播放优先级枚举
    Audio playback priority enumeration
    
    数值越小优先级越高
    Lower values indicate higher priority
    """
    EMERGENCY = 0      # 紧急音频（警告、错误）
    HIGH = 1          # 高优先级（重要通知）
    NORMAL = 2        # 正常优先级（对话、TTS）
    LOW = 3           # 低优先级（背景音、音效）
    BACKGROUND = 4    # 背景音频


@dataclass
class AudioTask:
    """
    音频播放任务
    Audio playback task
    """
    task_id: str
    priority: AudioPriority
    audio_type: str  # 'file', 'tts', 'system_sound', 'beep'
    audio_data: Dict[str, Any]  # 音频数据和参数
    volume: Optional[float] = None
    blocking: bool = False
    callback: Optional[Callable] = None
    created_time: float = field(default_factory=time.time)
    
    def __lt__(self, other):
        """优先级队列排序：优先级 > 创建时间"""
        if self.priority != other.priority:
            return self.priority < other.priority
        return self.created_time < other.created_time


class AudioQueueManager:
    """
    全局音频队列管理器
    Global Audio Queue Manager
    
    管理全局音频播放队列，支持优先级播放和打断机制
    Manages global audio playback queue with priority support and interrupt mechanism
    """
    
    def __init__(self, audio_player, config: Optional[Dict[str, Any]] = None):
        """
        初始化音频队列管理器
        Initialize audio queue manager
        
        Args:
            audio_player: AudioPlayer实例
            config: 配置参数
        """
        self.audio_player = audio_player
        self.config = config or {}
        
        # 队列管理
        self.priority_queue = PriorityQueue()
        self.current_task: Optional[AudioTask] = None
        self.task_counter = 0
        
        # 线程控制
        self.queue_thread: Optional[threading.Thread] = None
        self.queue_running = False
        self.queue_lock = threading.Lock()
        
        # 播放控制
        self.is_playing = False
        self.interrupt_requested = False
        self.pause_requested = False
        
        # 配置参数
        self.max_queue_size = self.config.get('max_queue_size', 100)
        self.auto_start = self.config.get('auto_start', True)
        self.enable_priority = self.config.get('enable_priority', True)
        
        # 回调函数
        self.on_task_start: Optional[Callable[[AudioTask], None]] = None
        self.on_task_complete: Optional[Callable[[AudioTask], None]] = None
        self.on_task_error: Optional[Callable[[AudioTask, Exception], None]] = None
        self.on_queue_empty: Optional[Callable[[], None]] = None
        
        # 统计信息
        self.total_tasks = 0
        self.completed_tasks = 0
        self.failed_tasks = 0
        
        # 日志
        self.logger = logging.getLogger(__name__)
        
        # 自动启动队列处理
        if self.auto_start:
            self.start_queue_processor()
    
    def start_queue_processor(self) -> bool:
        """
        启动队列处理线程
        Start queue processor thread
        
        Returns:
            bool: 启动是否成功
        """
        with self.queue_lock:
            if self.queue_running:
                self.logger.warning("Queue processor already running")
                return True
            
            try:
                self.queue_running = True
                self.queue_thread = threading.Thread(
                    target=self._process_queue,
                    daemon=True,
                    name="AudioQueueProcessor"
                )
                self.queue_thread.start()
                self.logger.info("Audio queue processor started")
                return True
            except Exception as e:
                self.logger.error(f"Failed to start queue processor: {e}")
                self.queue_running = False
                return False
    
    def stop_queue_processor(self) -> bool:
        """
        停止队列处理线程
        Stop queue processor thread
        
        Returns:
            bool: 停止是否成功
        """
        with self.queue_lock:
            if not self.queue_running:
                return True
            
            self.queue_running = False
            self.interrupt_current_playback()
            
            # 等待线程结束
            if self.queue_thread and self.queue_thread.is_alive():
                self.queue_thread.join(timeout=5.0)
                if self.queue_thread.is_alive():
                    self.logger.warning("Queue processor thread did not stop gracefully")
                    return False
            
            self.logger.info("Audio queue processor stopped")
            return True
    
    def add_audio_task(self, 
                      audio_type: str,
                      audio_data: Dict[str, Any],
                      priority: AudioPriority = AudioPriority.NORMAL,
                      volume: Optional[float] = None,
                      blocking: bool = False,
                      callback: Optional[Callable] = None) -> str:
        """
        添加音频播放任务到队列
        Add audio playback task to queue
        
        Args:
            audio_type: 音频类型 ('file', 'tts', 'system_sound', 'beep')
            audio_data: 音频数据和参数
            priority: 播放优先级
            volume: 音量 (0.0-1.0)
            blocking: 是否阻塞等待播放完成
            callback: 播放完成回调函数
            
        Returns:
            str: 任务ID
        """
        # 检查队列大小
        if self.priority_queue.qsize() >= self.max_queue_size:
            self.logger.warning(f"Queue is full (size: {self.max_queue_size}), dropping oldest low priority task")
            self._remove_low_priority_task()
        
        # 生成任务ID
        self.task_counter += 1
        task_id = f"audio_task_{self.task_counter}_{int(time.time() * 1000)}"
        
        # 创建任务
        task = AudioTask(
            task_id=task_id,
            priority=priority,
            audio_type=audio_type,
            audio_data=audio_data,
            volume=volume,
            blocking=blocking,
            callback=callback
        )
        
        # 添加到队列
        self.priority_queue.put(task)
        self.total_tasks += 1
        
        self.logger.debug(f"Added audio task {task_id} with priority {priority.name}")
        
        # 如果是高优先级任务，可能需要打断当前播放
        if priority <= AudioPriority.HIGH and self.is_playing:
            if self.current_task and self.current_task.priority > priority:
                self.logger.info(f"Interrupting current task for higher priority task {task_id}")
                self.interrupt_current_playback()
        
        return task_id
    
    def add_file_task(self, 
                     file_path: str,
                     priority: AudioPriority = AudioPriority.NORMAL,
                     volume: Optional[float] = None,
                     blocking: bool = False,
                     callback: Optional[Callable] = None) -> str:
        """
        添加音频文件播放任务
        Add audio file playback task
        """
        audio_data = {'file_path': file_path}
        return self.add_audio_task('file', audio_data, priority, volume, blocking, callback)
    
    def add_tts_task(self,
                    text: str,
                    priority: AudioPriority = AudioPriority.NORMAL,
                    volume: Optional[float] = None,
                    blocking: bool = False,
                    callback: Optional[Callable] = None) -> str:
        """
        添加TTS播放任务
        Add TTS playback task
        """
        audio_data = {'text': text}
        return self.add_audio_task('tts', audio_data, priority, volume, blocking, callback)
    
    def add_system_sound_task(self,
                             sound_name: str,
                             priority: AudioPriority = AudioPriority.HIGH,
                             volume: Optional[float] = None,
                             blocking: bool = False,
                             callback: Optional[Callable] = None) -> str:
        """
        添加系统提示音播放任务
        Add system sound playback task
        """
        audio_data = {'sound_name': sound_name}
        return self.add_audio_task('system_sound', audio_data, priority, volume, blocking, callback)
    
    def add_beep_task(self,
                     frequency: int = 1000,
                     duration: float = 0.5,
                     priority: AudioPriority = AudioPriority.NORMAL,
                     volume: Optional[float] = None,
                     blocking: bool = False,
                     callback: Optional[Callable] = None) -> str:
        """
        添加蜂鸣音播放任务
        Add beep playback task
        """
        audio_data = {'frequency': frequency, 'duration': duration}
        return self.add_audio_task('beep', audio_data, priority, volume, blocking, callback)
    
    def interrupt_current_playback(self) -> bool:
        """
        打断当前播放
        Interrupt current playback
        
        Returns:
            bool: 是否成功打断
        """
        if not self.is_playing:
            return True
        
        self.interrupt_requested = True
        
        # 停止AudioPlayer的播放
        if hasattr(self.audio_player, 'stop_playback'):
            self.audio_player.stop_playback()
        
        self.logger.info("Playback interruption requested")
        return True
    
    def clear_queue(self, priority_threshold: Optional[AudioPriority] = None) -> int:
        """
        清空播放队列
        Clear playback queue
        
        Args:
            priority_threshold: 只清除低于此优先级的任务
            
        Returns:
            int: 清除的任务数量
        """
        cleared_count = 0
        
        if priority_threshold is None:
            # 清空所有任务
            while not self.priority_queue.empty():
                try:
                    self.priority_queue.get_nowait()
                    cleared_count += 1
                except Empty:
                    break
        else:
            # 只清除低优先级任务
            temp_tasks = []
            while not self.priority_queue.empty():
                try:
                    task = self.priority_queue.get_nowait()
                    if task.priority <= priority_threshold:
                        temp_tasks.append(task)
                    else:
                        cleared_count += 1
                except Empty:
                    break
            
            # 重新添加保留的任务
            for task in temp_tasks:
                self.priority_queue.put(task)
        
        self.logger.info(f"Cleared {cleared_count} tasks from queue")
        return cleared_count
    
    def pause_queue(self) -> bool:
        """
        暂停队列处理
        Pause queue processing
        """
        self.pause_requested = True
        self.logger.info("Queue processing paused")
        return True
    
    def resume_queue(self) -> bool:
        """
        恢复队列处理
        Resume queue processing
        """
        self.pause_requested = False
        self.logger.info("Queue processing resumed")
        return True
    
    def get_queue_status(self) -> Dict[str, Any]:
        """
        获取队列状态信息
        Get queue status information
        
        Returns:
            Dict: 队列状态信息
        """
        return {
            'queue_size': self.priority_queue.qsize(),
            'is_playing': self.is_playing,
            'current_task_id': self.current_task.task_id if self.current_task else None,
            'queue_running': self.queue_running,
            'paused': self.pause_requested,
            'total_tasks': self.total_tasks,
            'completed_tasks': self.completed_tasks,
            'failed_tasks': self.failed_tasks,
            'success_rate': self.completed_tasks / max(1, self.total_tasks) * 100
        }
    
    def set_callbacks(self,
                     on_task_start: Optional[Callable[[AudioTask], None]] = None,
                     on_task_complete: Optional[Callable[[AudioTask], None]] = None,
                     on_task_error: Optional[Callable[[AudioTask, Exception], None]] = None,
                     on_queue_empty: Optional[Callable[[], None]] = None):
        """
        设置回调函数
        Set callback functions
        """
        self.on_task_start = on_task_start
        self.on_task_complete = on_task_complete
        self.on_task_error = on_task_error
        self.on_queue_empty = on_queue_empty
    
    def _process_queue(self):
        """
        队列处理主循环
        Main queue processing loop
        """
        self.logger.info("Audio queue processor started")
        
        while self.queue_running:
            try:
                # 检查暂停状态
                if self.pause_requested:
                    time.sleep(0.1)
                    continue
                
                # 获取下一个任务
                try:
                    task = self.priority_queue.get(timeout=1.0)
                except Empty:
                    # 队列为空，触发回调
                    if self.on_queue_empty:
                        try:
                            self.on_queue_empty()
                        except Exception as e:
                            self.logger.error(f"Error in queue empty callback: {e}")
                    continue
                
                # 执行任务
                self._execute_task(task)
                
            except Exception as e:
                self.logger.error(f"Error in queue processing: {e}")
                time.sleep(0.1)
        
        self.logger.info("Audio queue processor stopped")
    
    def _execute_task(self, task: AudioTask):
        """
        执行音频播放任务
        Execute audio playback task
        """
        self.current_task = task
        self.is_playing = True
        self.interrupt_requested = False
        
        try:
            # 触发任务开始回调
            if self.on_task_start:
                self.on_task_start(task)
            
            self.logger.debug(f"Executing task {task.task_id} (type: {task.audio_type})")
            
            # 根据任务类型执行播放
            success = False
            if task.audio_type == 'file':
                success = self._play_file_task(task)
            elif task.audio_type == 'tts':
                success = self._play_tts_task(task)
            elif task.audio_type == 'system_sound':
                success = self._play_system_sound_task(task)
            elif task.audio_type == 'beep':
                success = self._play_beep_task(task)
            else:
                raise ValueError(f"Unknown audio type: {task.audio_type}")
            
            # 更新统计
            if success:
                self.completed_tasks += 1
                self.logger.debug(f"Task {task.task_id} completed successfully")
                
                # 触发完成回调
                if self.on_task_complete:
                    self.on_task_complete(task)
                
                # 执行任务自定义回调
                if task.callback:
                    task.callback()
            else:
                self.failed_tasks += 1
                self.logger.warning(f"Task {task.task_id} failed")
                
        except Exception as e:
            self.failed_tasks += 1
            self.logger.error(f"Error executing task {task.task_id}: {e}")
            
            # 触发错误回调
            if self.on_task_error:
                try:
                    self.on_task_error(task, e)
                except Exception as callback_error:
                    self.logger.error(f"Error in task error callback: {callback_error}")
        
        finally:
            self.current_task = None
            self.is_playing = False
            self.interrupt_requested = False
    
    def _play_file_task(self, task: AudioTask) -> bool:
        """
        执行文件播放任务
        Execute file playback task
        """
        file_path = task.audio_data['file_path']
        
        if not Path(file_path).exists():
            self.logger.error(f"Audio file not found: {file_path}")
            return False
        
        return self.audio_player.play_file(
            file_path, 
            volume=task.volume, 
            blocking=True  # 队列管理器中总是阻塞播放
        )
    
    def _play_tts_task(self, task: AudioTask) -> bool:
        """
        执行TTS播放任务
        Execute TTS playback task
        """
        # 这里需要集成TTS功能，暂时返回False
        # TODO: 集成TextToSpeechClient
        text = task.audio_data['text']
        self.logger.warning(f"TTS playback not implemented yet for text: {text}")
        return False
    
    def _play_system_sound_task(self, task: AudioTask) -> bool:
        """
        执行系统提示音播放任务
        Execute system sound playback task
        """
        sound_name = task.audio_data['sound_name']
        return self.audio_player.play_system_sound(
            sound_name,
            volume=task.volume,
            blocking=True
        )
    
    def _play_beep_task(self, task: AudioTask) -> bool:
        """
        执行蜂鸣音播放任务
        Execute beep playback task
        """
        frequency = task.audio_data.get('frequency', 1000)
        duration = task.audio_data.get('duration', 0.5)
        
        return self.audio_player.play_beep(
            frequency=frequency,
            duration=duration,
            volume=task.volume
        )
    
    def _remove_low_priority_task(self):
        """
        移除一个低优先级任务为新任务腾出空间
        Remove a low priority task to make room for new task
        """
        temp_tasks = []
        removed = False
        
        # 从队列中取出所有任务
        while not self.priority_queue.empty():
            try:
                task = self.priority_queue.get_nowait()
                if not removed and task.priority >= AudioPriority.LOW:
                    # 移除第一个低优先级任务
                    removed = True
                    self.logger.debug(f"Removed low priority task {task.task_id} to make room")
                else:
                    temp_tasks.append(task)
            except Empty:
                break
        
        # 重新添加保留的任务
        for task in temp_tasks:
            self.priority_queue.put(task)
    
    def cleanup(self):
        """
        清理队列管理器资源
        Cleanup queue manager resources
        
        This is an alias for shutdown() method to maintain interface consistency
        """
        self.shutdown()
    
    def shutdown(self):
        """
        关闭队列管理器
        Shutdown queue manager
        """
        self.logger.info("Shutting down audio queue manager")
        
        # 停止队列处理
        self.stop_queue_processor()
        
        # 清空队列
        self.clear_queue()
        
        # 重置状态
        self.current_task = None
        self.is_playing = False
        self.interrupt_requested = False
        self.pause_requested = False
        
        self.logger.info("Audio queue manager shutdown complete")
    
    def __enter__(self):
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.shutdown()